/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <gtest/gtest.h>

#include "channel_operations_mock.h"
#include "module_common_core.h"
#include "test_helpers.h"

namespace OHOS {
namespace SeBaseServices {
namespace UnitTest {
using namespace testing;
TEST(ModuleCommonCoreTest, SeCommonIsServiceAvailableInvalidInput1)
{
    ResultCode ret = SeCommonIsServiceAvailable(nullptr, SERVICE_ID_PIN_AUTH, nullptr);
    EXPECT_EQ(ret, INVALID_PARA_NULL_PTR);
}

TEST(ModuleCommonCoreTest, SeCommonIsServiceAvailableInvalidInput2)
{
    CardChannel channel;
    ResultCode ret = SeCommonIsServiceAvailable(&channel, SERVICE_ID_PIN_AUTH, nullptr);
    EXPECT_EQ(ret, INVALID_PARA_NULL_PTR);
}

TEST(ModuleCommonCoreTest, SeCommonIsServiceAvailableGoodCaseTotalReturn)
{
    auto transmit = [](SecureElementContext *, uint8_t *response, uint32_t *responseLen) -> ResultCode {
        std::string out = "1234"                     // 2-bytes version
                          "88884790"                 // 4-bytes vendor
                          "0102030405060708090A0B0C" // 12-bytes conf
                          "aabbccdd11223344"         // 8-bytes status
                          "9000";                    // 2-bytes sw

        TestHelpers::StringFillUp(out, response, responseLen);
        return SUCCESS;
    };

    ChannelOperationsMock mock;
    EXPECT_CALL(mock, ChannelGetOpenResponse).Times(Exactly(1)).WillOnce(Invoke(transmit));
    CardChannel channel = {
        .context = nullptr,
        .oper = {.getOpenResponse = &ChannelOperationsMock::MockChannelGetOpenResponse},
    };

    SeServiceStatus status;
    ResultCode ret = SeCommonIsServiceAvailable(&channel, SERVICE_ID_PIN_AUTH, &status);
    EXPECT_EQ(ret, SUCCESS);
    EXPECT_EQ(status.available, 1);
    EXPECT_EQ(status.version, 0x3412);
    EXPECT_EQ(status.config.vendor, 0x90478888);
    EXPECT_EQ(TestHelpers::VectorToHexString(status.config.config, SERVICE_STATUS_MAX_CONFIG_LEN),
        "0102030405060708090A0B0C");
    EXPECT_EQ(TestHelpers::VectorToHexString(status.status, SERVICE_STATUS_DATA_LEN), "AABBCCDD11223344");
}

TEST(ModuleCommonCoreTest, SeCommonIsServiceAvailableGoodCaseShortReturn)
{
    auto transmit = [](SecureElementContext *, uint8_t *response, uint32_t *responseLen) -> ResultCode {
        std::string out = "1234"                     // 2-bytes version
                          "88884790"                 // 4-bytes vendor
                          "0102030405060708090A0B0C" // 12-bytes conf
                          "9000";                    // 2-bytes sw

        TestHelpers::StringFillUp(out, response, responseLen);
        return SUCCESS;
    };

    ChannelOperationsMock mock;
    EXPECT_CALL(mock, ChannelGetOpenResponse).Times(Exactly(1)).WillOnce(Invoke(transmit));
    CardChannel channel = {
        .context = nullptr,
        .oper = {.getOpenResponse = &ChannelOperationsMock::MockChannelGetOpenResponse},
    };

    SeServiceStatus status;
    ResultCode ret = SeCommonIsServiceAvailable(&channel, SERVICE_ID_PIN_AUTH, &status);
    EXPECT_EQ(ret, SUCCESS);
    EXPECT_EQ(status.available, 1);
    EXPECT_EQ(status.version, 0x3412);
    EXPECT_EQ(status.config.vendor, 0x90478888);
    EXPECT_EQ(TestHelpers::VectorToHexString(status.config.config, SERVICE_STATUS_MAX_CONFIG_LEN),
        "0102030405060708090A0B0C");
    EXPECT_EQ(TestHelpers::VectorToHexString(status.status, SERVICE_STATUS_DATA_LEN), "0000000000000000");
}

TEST(ModuleCommonCoreTest, SeCommonIsServiceAvailableGoodCaseOldWeaver)
{
    auto transmit = [](SecureElementContext *, uint8_t *response, uint32_t *responseLen) -> ResultCode {
        TestHelpers::StringFillUp("9000", response, responseLen);
        return SUCCESS;
    };

    ChannelOperationsMock mock;
    EXPECT_CALL(mock, ChannelGetOpenResponse).Times(Exactly(1)).WillOnce(Invoke(transmit));
    CardChannel channel = {
        .context = nullptr,
        .oper = {.getOpenResponse = &ChannelOperationsMock::MockChannelGetOpenResponse},
    };

    SeServiceStatus status;
    ResultCode ret = SeCommonIsServiceAvailable(&channel, SERVICE_ID_PIN_AUTH, &status);
    EXPECT_EQ(ret, SUCCESS);
    EXPECT_EQ(status.available, 1);
    EXPECT_EQ(status.version, 0);
    EXPECT_EQ(status.config.vendor, 0);
    EXPECT_EQ(TestHelpers::VectorToHexString(status.config.config, SERVICE_STATUS_MAX_CONFIG_LEN),
        "000000000000000000000000");
    EXPECT_EQ(TestHelpers::VectorToHexString(status.status, SERVICE_STATUS_DATA_LEN), "0000000000000000");
}

TEST(ModuleCommonCoreTest, SeCommonIsServiceAvailableNot9000)
{
    auto transmit = [](SecureElementContext *, uint8_t *response, uint32_t *responseLen) -> ResultCode {
        std::string out = "1234"                     // 2-bytes version
                          "88884790"                 // 4-bytes vendor
                          "0102030405060708090A0B0C" // 12-bytes conf
                          "6985";                    //  2-bytes sw

        TestHelpers::StringFillUp(out, response, responseLen);
        return SUCCESS;
    };

    ChannelOperationsMock mock;
    EXPECT_CALL(mock, ChannelGetOpenResponse).Times(Exactly(1)).WillOnce(Invoke(transmit));
    CardChannel channel = {
        .context = nullptr,
        .oper = {.getOpenResponse = &ChannelOperationsMock::MockChannelGetOpenResponse},
    };

    SeServiceStatus status;
    ResultCode ret = SeCommonIsServiceAvailable(&channel, SERVICE_ID_PIN_AUTH, &status);
    EXPECT_EQ(ret, RES_APDU_SW_ERR);
    EXPECT_EQ(status.available, 0);
}

TEST(SecStorageCoreTest, SeCommonSetServiceConfigurationSuccess)
{
    auto transmit = [](SecureElementContext *context, const uint8_t *command, uint32_t commandLen, uint8_t *response,
                        uint32_t *responseLen) -> ResultCode {
        (void)context;
        auto input = TestHelpers::VectorToHexString(command, commandLen);
        auto expect = "80300002"                 // apdu header
                      "10"                       // lc = 16
                      "78563412"                 // key = 0x12345678
                      "112233445566778899AABBCC" // config
                      "00";                      // expect le = 00
        EXPECT_EQ(input, expect);

        TestHelpers::StringFillUp("9000", response, responseLen);
        return SUCCESS;
    };
    ChannelOperationsMock mock;
    EXPECT_CALL(mock, ChannelTransmit).Times(Exactly(1)).WillOnce(Invoke(transmit));
    CardChannel channel = {.context = nullptr, .oper = {.transmit = &ChannelOperationsMock::MockChannelTransmit}};

    uint32_t lock = 1;
    SeServiceConfig config = {
        .vendor = 0x12345678,
        .config = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc},
    };

    auto ret = SeCommonSetServiceConfiguration(&channel, SERVICE_ID_SEC_STORAGE, lock, &config);
    EXPECT_EQ(ret, SUCCESS);
}
} // namespace UnitTest
} // namespace SeBaseServices
} // namespace OHOS